﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfellerpp
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Linq;
using System.Reflection;
using InterLinq.Base;
using Sebarf.Core.Interfaces;
using Sebarf.Diagnostics.Interfaces;
using Sebastof.Core.Services.Interfaces;

#endregion

namespace InterLinq.Sebarf {
	/// <summary>
	/// Description of the class
	/// </summary>
	public class ExecuteLinqQueryRequestHandler : RequestHandler<ExecuteLinqQueryRequest> {
		#region Public Properties

		public IQueryHandler QueryHandler { get; set; }

		#endregion

		#region Public Methods

		protected override object OnProcessRequest(ExecuteLinqQueryRequest request, IServiceLocatorService serviceLocator) {
			ISerializableExpression expression = request.SerializableExpression;
#if DEBUG
			Console.WriteLine(expression);
			Console.WriteLine();
#endif
			object returnValue = null;

			MethodInfo mInfo;
			var realType = (Type)expression.Type.GetClrVersion();
			if (typeof(IQueryable).IsAssignableFrom(realType) && realType.GetGenericArguments().Length == 1) {
				// Find Generic Retrieve Method

				mInfo = GetType().GetMethod("RetrieveGeneric");
				mInfo = mInfo.MakeGenericMethod(realType.GetGenericArguments()[0]);
				returnValue = mInfo.Invoke(this, new object[] { expression, serviceLocator });
			}
			else {
				// Find Non-Generic Retrieve Method
				//mInfo = GetType().GetMethod("RetrieveNonGenericObject");
				returnValue = RetrieveNonGenericObject(expression, serviceLocator);
			}

#if DEBUG

			//System.IO.MemoryStream ms = new System.IO.MemoryStream();
			//new System.Runtime.Serialization.NetDataContractSerializer().Serialize(ms, returnValue);
#endif

			return returnValue;
		}

		#endregion

		#region Private Methods

		/// <summary>
		/// Retrieves data from the server by an <see cref="SerializableExpression">Expression</see> tree.
		/// </summary>
		/// <typeparam name="T">Type of the <see cref="IQueryable"/>.</typeparam>
		/// <param name="serializableExpression">
		///     <see cref="SerializableExpression">Expression</see> tree 
		///     containing selection and projection.
		/// </param>
		/// <returns>Returns requested data.</returns>
		/// <seealso cref="IQueryRemoteHandler.Retrieve"/>
		/// <remarks>
		/// This method's return type depends on the submitted 
		/// <see cref="SerializableExpression">Expression</see> tree.
		/// Here some examples ('T' is the requested type):
		/// <list type="list">
		///     <listheader>
		///         <term>Method</term>
		///         <description>Return Type</description>
		///     </listheader>
		///     <item>
		///         <term>Select(...)</term>
		///         <description>T[]</description>
		///     </item>
		///     <item>
		///         <term>First(...), Last(...)</term>
		///         <description>T</description>
		///     </item>
		///     <item>
		///         <term>Count(...)</term>
		///         <description><see langword="int"/></description>
		///     </item>
		///     <item>
		///         <term>Contains(...)</term>
		///         <description><see langword="bool"/></description>
		///     </item>
		/// </list>
		/// </remarks>
		public object RetrieveGeneric<T>(ISerializableExpression serializableExpression, IServiceLocatorService locator) {
			try {
				QueryHandler.StartSession();
				var query = serializableExpression.Convert(QueryHandler) as IQueryable<T>;

				if (QueryHandler.LockOfDataSource != null) {
					QueryHandler.LockOfDataSource.AcquireReaderLock(-1);
				}

				T[] returnValue = null;
				try {
					returnValue = query.ToArray();
				}
				catch (Exception ex) {
					Logger.WriteError(ex.Message);
				}
				finally {
					if (QueryHandler.LockOfDataSource != null) {
						QueryHandler.LockOfDataSource.ReleaseReaderLock();
					}
				}
				object convertedReturnValue =
					locator.GetRegisteredService<IObjectTransmissionService>().PrepareObjectForTransmission(returnValue);
				return convertedReturnValue;
			}
			catch (Exception ex) {
				Logger.WriteError(ex.Message + "\t" + ex.StackTrace);
				Check.AssertDebug(false, ex.Message + "\t" + ex.StackTrace);
				throw;
			}
			finally {
				QueryHandler.CloseSession();
			}
		}

		/// <summary>
		/// Retrieves data from the server by an <see cref="SerializableExpression">Expression</see> tree.
		/// </summary>
		/// <param name="serializableExpression">
		///     <see cref="SerializableExpression">Expression</see> tree 
		///     containing selection and projection.
		/// </param>
		/// <returns>Returns requested data.</returns>
		/// <remarks>
		/// This method's return type depends on the submitted 
		/// <see cref="SerializableExpression">Expression</see> tree.
		/// Here some examples ('T' is the requested type):
		/// <list type="list">
		///     <listheader>
		///         <term>Method</term>
		///         <description>Return Type</description>
		///     </listheader>
		///     <item>
		///         <term>Select(...)</term>
		///         <description>T[]</description>
		///     </item>
		///     <item>
		///         <term>First(...), Last(...)</term>
		///         <description>T</description>
		///     </item>
		///     <item>
		///         <term>Count(...)</term>
		///         <description><see langword="int"/></description>
		///     </item>
		///     <item>
		///         <term>Contains(...)</term>
		///         <description><see langword="bool"/></description>
		///     </item>
		/// </list>
		/// </remarks>
		/// <seealso cref="IQueryRemoteHandler.Retrieve"/>
		public object RetrieveNonGenericObject(ISerializableExpression serializableExpression, IServiceLocatorService locator) {
			try {
				Logger.WriteDebug(serializableExpression.ToString());

				QueryHandler.StartSession();

				object returnValue = null;
				if (QueryHandler.LockOfDataSource != null) {
					QueryHandler.LockOfDataSource.AcquireReaderLock(-1);
				}

				try {
					returnValue = serializableExpression.Convert(QueryHandler);
				}
				finally {
					if (QueryHandler.LockOfDataSource != null) {
						QueryHandler.LockOfDataSource.ReleaseReaderLock();
					}
				}

				object convertedReturnValue =
					locator.GetRegisteredService<IObjectTransmissionService>().PrepareObjectForTransmission(returnValue);
				QueryHandler.CloseSession();
				return convertedReturnValue;
			}
			catch (Exception ex) {
				Check.AssertException(false, ex.Message);
			}
			return null;
		}

		#endregion
	}
}